{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit DesignerPropsInspector;

interface

uses Classes, Types, Graphics, Controls, StdCtrls, Menus, JvInspector, TypInfo,
     UIObjects, AHMTypes;

const
  // Various strings used throughout our editors
  CLICK_TO_EDIT = 'Click to edit';
  BROWSE_FILE_TITLE = 'Select file';
  COPY_FILE_CONFIRM = 'Would you like to copy this file into the current ' +
                      'theme resources directory?';

type
  TAHMInspectorPropData = class(TJvInspectorPropData);

  TAHMInspectorCategoryItem = class(TJvInspectorCustomCategoryItem)
  private
    FUIObject: TAHMUIObject;
  public
    property UIObject: TAHMUIObject read FUIObject write FUIObject;
  end;

  TAHMCustomInspectorData = class(TJvCustomInspectorData);

  TAHMInspectorHintItem = class(TJvCustomInspectorItem);

  // Custom property inspector classes

  TAHMInspectorStringItem = class(TJvInspectorStringItem)
  protected
    class function GetTypeInfo: Pointer; virtual;
    function GetUIObject: TAHMUIObject;
    procedure SetDisplayValue(const Value: string); override;
  public
    constructor Create(const AParent: TJvCustomInspectorItem; const AData: TJvCustomInspectorData); override;
    destructor Destroy; override;
    class procedure RegisterAsDefaultItem;
    class procedure UnregisterAsDefaultItem;
    property UIObject: TAHMUIObject read GetUIObject;
  end;

  TAHMInspectorFilenameItem = class(TAHMInspectorStringItem)
  protected
    class function GetTypeInfo: Pointer; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure Edit; override;
  end;

  TAHMInspectorMemoStringItem = class(TAHMInspectorStringItem)
  protected
    class function GetTypeInfo: Pointer; override;
    function GetDisplayValue: String; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure Edit; override;
  end;

  TAHMInspectorColourStringItem = class(TAHMInspectorStringItem)
  protected
    class function GetTypeInfo: Pointer; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure Edit; override;
  end;

  TAHMInspectorMetaStringItem = class(TAHMInspectorStringItem)
  protected
    class function GetTypeInfo: Pointer; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure GetValueList(const Strings: TStrings); override;
  end;

  TAHMInspectorFunctionStringItem = class(TAHMInspectorStringItem)
  protected
    class function GetTypeInfo: Pointer; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure GetValueList(const Strings: TStrings); override;
  end;

  TAHMInspectorTextStringItem = class(TAHMInspectorStringItem)
  protected
    class function GetTypeInfo: Pointer; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure Edit; override;
  end;

  TAHMInspectorTypefaceItem = class(TAHMInspectorStringItem)
  protected
    class function GetTypeInfo: Pointer; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure Edit; override;
  end;

  TAHMInspectorEnumItem = class(TJvInspectorEnumItem)
  private
    FValues: TStringList;
  protected
    function FormatValueName(const Name: String): String;
    function GetDisplayValue: String; override;
    procedure GetValueList(const Strings: TStrings); override;
    procedure SetDisplayValue(const Value: String); override;
  public
    constructor Create(const AParent: TJvCustomInspectorItem; const AData: TJvCustomInspectorData); override;
    destructor Destroy; override;
    class procedure RegisterAsDefaultItem;
    class procedure UnregisterAsDefaultItem;
  end;

  TAHMInspectorSingleItem = class(TJvInspectorFloatItem)
  protected
    class function GetTypeInfo: Pointer; virtual;
  public
    constructor Create(const AParent: TJvCustomInspectorItem; const AData: TJvCustomInspectorData); override;
    class procedure RegisterAsDefaultItem;
    class procedure UnregisterAsDefaultItem;
  end;

  TAHMInspectorClassItem = class(TJvInspectorClassItem)
  protected
    FUIObject: TAHMUIObject;
    class function GetTypeInfo: Pointer; virtual;
    function GetUIObject: TAHMUIObject;
    function GetSelectedObject: TAHMUIObject;
    procedure SetSelectedObject(Selected: TAHMUIObject);
    procedure EditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer); override;
    procedure SetItemClassFlags(Value: TInspectorClassFlags); override;
  public
    constructor Create(const AParent: TJvCustomInspectorItem;
      const AData: TJvCustomInspectorData); override;
    class procedure RegisterAsDefaultItem;
    class procedure UnregisterAsDefaultItem;
    property UIObject: TAHMUIObject read GetUIObject;
    property SelectedObject: TAHMUIObject read GetSelectedObject write SetSelectedObject;
  end;

  TAHMInspectorClassListItem = class(TAHMInspectorClassItem)
  protected
    procedure SetFlags(const Value: TInspectorItemFlags); override;
  end;

  TAHMInspectorUIListItem = class(TAHMInspectorClassItem)
  protected
    function GetDisplayValue: string; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure Edit; override;
  end;

  TAHMInspectorUIStateListItem = class(TAHMInspectorUIListItem)
  protected
    class function GetTypeInfo: Pointer; override;
  end;

  TAHMInspectorUIActionsItem = class(TAHMInspectorUIListItem)
  protected
    class function GetTypeInfo: Pointer; override;
  end;

  TAHMInspectorUIAnimationsItem = class(TAHMInspectorUIListItem)
  protected
    class function GetTypeInfo: Pointer; override;
  end;

  TAHMInspectorUIControlsItem = class(TAHMInspectorUIListItem)
  protected
    class function GetTypeInfo: Pointer; override;
  end;

  TAHMInspectorUIContainersItem = class(TAHMInspectorUIListItem)
  protected
    class function GetTypeInfo: Pointer; override;
  end;

  TAHMInspectorUILayoutPositionsItem = class(TAHMInspectorUIListItem)
  protected
    class function GetTypeInfo: Pointer; override;
  end;

  TAHMInspectorUIMacroFunctionsItem = class(TAHMInspectorUIListItem)
  protected
    class function GetTypeInfo: Pointer; override;
  end;

  TAHMInspectorUIMetaValuesItem = class(TAHMInspectorUIListItem)
  protected
    class function GetTypeInfo: Pointer; override;
  end;

  TAHMInspectorUIObjectItem = class(TAHMInspectorClassListItem)
  private
  protected
    class function GetTypeInfo: Pointer; override;
    procedure GetValueList(const Strings: TStrings); override;
    procedure SetDisplayValue(const Value: string); override;
    procedure BuildValueList(const Strings: TStrings; const List: TAHMUIObjectList); overload;
    procedure BuildValueList(const Strings: TStrings; const List: TAHMUIObjectList;
                             FilterClass: TAHMUIObjectClass); overload;
  public
    function GetObjectList: TAHMUIObjectList; virtual;
  end;

  TAHMInspectorUIAncestorItem = class(TAHMInspectorUIObjectItem)
  protected
    procedure GetValueList(const Strings: TStrings); override;
  end;

  TAHMInspectorUIColourItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
    procedure SetFlags(const Value: TInspectorItemFlags); override;
    procedure SetRects(const RectKind: TInspectorPaintRect; Value: TRect); override;
    procedure DoDrawListItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
    procedure DoMeasureListItem(Control: TWinControl; Index: Integer; var Height: Integer); override;
    procedure DoMeasureListItemWidth(Control: TWinControl; Index: Integer; var Width: Integer); override;
  public
    procedure DrawValue(const ACanvas: TCanvas); override;
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIFillItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIPlasmaItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUICaptionItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIFontItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIBitmapItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIBackgroundItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIForegroundItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUILayoutItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIPlaceItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIEffectItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIGridItemItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIDisplayObjectItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIControlItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
  public
    function GetObjectList: TAHMUIObjectList; override;
  end;

  TAHMInspectorUIInteractiveControlItem = class(TAHMInspectorUIObjectItem)
  protected
    class function GetTypeInfo: Pointer; override;
    procedure GetValueList(const Strings: TStrings); override;
  end;

  procedure AddInspectorUIObject(Inspector: TJvInspector; Instance: TAHMUIObject);
  function GetInspectorUIObjectHint(Item: TJvCustomInspectorItem): String;
  function GetSelectedUIObject(Item: TJvCustomInspectorItem): TAHMUIObject;

  procedure PaintColourValue(UIObject: TAHMUIObject; const ObjectName: string;
                             const ACanvas: TCanvas; const ARect: TRect);

implementation

uses Windows, SysUtils, ApplicationManager, Colours, Fills, Plasma, Captions,
     Fonts, Bitmaps, Places, Layouts, Effects, BaseControls, Backgrounds,
     Foregrounds, Animators, Containers, Screens, Actions, Macros, Languages,
     MetaValues, GridItems, JclRTTI, DesignerTextEdit;

type
  TColorQuad = packed record
    Red: Byte;
    Green: Byte;
    Blue: Byte;
    Alpha: Byte;
  end;

// Support methods

procedure AddInspectorUIObject(Inspector: TJvInspector; Instance: TAHMUIObject);
var
  InspCat: TAHMInspectorCategoryItem;
  NewItem: TJvCustomInspectorItem;
  Properties: TAHMUIPropertyList;
  PropInfo: PPropInfo;
  i, j: Integer;
begin
  if (Instance <> nil) then
  begin
    // Build a list of properties for this object
    Properties := TAHMUIPropertyList.Create;
    Instance.BuildProperties(Properties);
    Inspector.BeginUpdate;
    try
      for i := 0 to Pred(Properties.Count) do
      begin
        // Look for an existing category node for this property
        InspCat := nil;
        for j := 0 to Pred(Inspector.Root.Count) do
          if Inspector.Root[j].DisplayName = Properties[i].Category then
          begin
            InspCat := TAHMInspectorCategoryItem(Inspector.Root[j]);
            Break;
          end;

        // Create a new category node if we didn't find one
        if InspCat = nil then
        begin
          InspCat := TAHMInspectorCategoryItem.Create(Inspector.Root, nil);
          InspCat.DisplayName := Properties[i].Category;
          InspCat.UIObject := Instance;
          InspCat.SortKind := iskName;
          InspCat.Expanded := True;
        end;

        // Add property to this category
        PropInfo := GetPropInfo(Instance, Properties[i].PropertyName);
        NewItem := TAHMInspectorPropData.New(InspCat, Instance, PropInfo);
        NewItem.DisplayName := Properties[i].DisplayName;

        // Add a hidden child node to store hint for this property
        with TAHMInspectorHintItem.Create(NewItem, nil) do
        begin
          DisplayName := HINT_PREFIX + Properties[i].HintText;
          Visible := False;
        end;
      end;
    finally
      Inspector.EndUpdate;
      Properties.Free;
    end;
  end;
end;

function GetInspectorUIObjectHint(Item: TJvCustomInspectorItem): String;
begin
  // Hint is stored in hidden child node of each property
  if Assigned(Item) and (Item.Data is TJvInspectorPropData) and (Item.Count > 0) then
    Result := Item[0].DisplayName
  else
    Result := '';
end;

function GetSelectedUIObject(Item: TJvCustomInspectorItem): TAHMUIObject;
begin
  // Identify lowest level target UIObject instance - note that this
  // may be different from the root UIObject if this is a nested property
  if Item is TAHMInspectorUIObjectItem then
    Result := TAHMInspectorUIObjectItem(Item).UIObject
  else if Item.Parent is TAHMInspectorUIObjectItem then
    Result := TAHMUIObject(Item.Parent.Data.AsOrdinal)
  else if Item.Parent is TAHMInspectorCategoryItem then
    Result := TAHMInspectorCategoryItem(Item.Parent).UIObject
  else
    Result := nil;
end;

function BorderColour(const Background, Internal: TColor): TColor;
var
  BckRGB: TColor;
  IntRGB: TColor;

  function IsLightColor(const RGB: TColor): Boolean;
  begin
    with TColorQuad(RGB) do
      Result := (Red > 192) or (Green > 192) or (Blue > 192);
  end;

begin
  BckRGB := ColorToRGB(Background);
  IntRGB := ColorToRGB(Internal);

  if IsLightColor(BckRGB) and IsLightColor(IntRGB) then
    Result := clBlack
  else
  if not IsLightColor(BckRGB) and not IsLightColor(IntRGB) then
    Result := clWhite
  else
    Result := Internal;
end;

procedure PaintColourValue(UIObject: TAHMUIObject; const ObjectName: string; const ACanvas: TCanvas; const ARect: TRect);
const
  TH = 13;
var
  BoxRect: TRect;
  bc: TColor;
  pc: TColor;
  Colour: TAHMColour;
  txtRect: TRect;
begin
  BoxRect.Left := ARect.Left + (ARect.Bottom - ARect.Top - TH) div 2;
  BoxRect.Top := ARect.Top + BoxRect.Left - ARect.Left;
  BoxRect.Right := BoxRect.Left + TH;
  BoxRect.Bottom := BoxRect.Top + TH;
  with ACanvas do
  begin
    if (UIObject is TAHMColour) then
    begin
      Colour := TAHMColour(UIObject);
      if Assigned(Colour.Colour) and (Colour.Colour.InternalColor <> clNone) then
      begin
        bc := Brush.Color;
        pc := Pen.Color;
        try
          Brush.Color := Colour.Colour.InternalColor;
          Pen.Color := BorderColour(bc, Brush.Color);
          Rectangle(BoxRect);
        finally
          Pen.Color := pc;
          Brush.Color := bc;
        end;
      end;
    end;
   txtRect := ARect;
   txtRect.Left := txtRect.Left + (txtRect.Bottom-txtRect.Top)+ 1;
   TextRect(txtRect, txtRect.Left, BoxRect.Top, ObjectName);
  end;
end;


// TAHMInspectorStringItem

constructor TAHMInspectorStringItem.Create(const AParent: TJvCustomInspectorItem; const AData: TJvCustomInspectorData);
begin
  inherited;

end;

destructor TAHMInspectorStringItem.Destroy;
begin

  inherited;
end;

function TAHMInspectorStringItem.GetUIObject: TAHMUIObject;
begin
  Result := TAHMInspectorCategoryItem(Category).UIObject;
end;

procedure TAHMInspectorStringItem.SetDisplayValue(const Value: string);
begin
  if Value = EMPTY_UIOBJECT_NAME then
  begin
    inherited SetDisplayValue('');
    Clear;
  end
  else
    inherited SetDisplayValue(Value);
end;

class function TAHMInspectorStringItem.GetTypeInfo: Pointer;
begin
  // Descendants will override this to provide typeinfo for required type
  Result := nil;
end;

class procedure TAHMInspectorStringItem.RegisterAsDefaultItem;
begin
  with TJvCustomInspectorData.ItemRegister do
  begin
    if IndexOf(Self) = -1 then
      Add(TJvInspectorTypeInfoRegItem.Create(Self, GetTypeInfo));
  end;
end;

class procedure TAHMInspectorStringItem.UnregisterAsDefaultItem;
begin
  TJvCustomInspectorData.ItemRegister.Delete(Self);
end;

// TAHMInspectorFilenameItem

class function TAHMInspectorFilenameItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMFilename);
end;

procedure TAHMInspectorFilenameItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifEditButton]);
end;

procedure TAHMInspectorFilenameItem.Edit;
begin
  // Use standard modify method to edit filename
  if UIObject.Modify then
    DoneEdit(True); // Cancel default editor

  // Re-initialise inspector display edit button properly
  InitEdit;
  Inspector.Invalidate;
end;

// TAHMInspectorMemoStringItem

class function TAHMInspectorMemoStringItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMMemoString);
end;

function TAHMInspectorMemoStringItem.GetDisplayValue: String;
var
  Obj: TAHMMemoString;
begin
  Obj := Data.AsString;
  Result := StringReplace(Obj, sLineBreak, ' ', [rfReplaceAll]);
end;

procedure TAHMInspectorMemoStringItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifEditButton]);
end;

procedure TAHMInspectorMemoStringItem.Edit;
var
  Value: String;
begin
  Value := Data.AsString;

  // Use text dialog to edit value
  if TfrmTextProperties.EditText(Value, DisplayName, UIObject) then
  begin
    Data.AsString := Value;
    UIObject.Modified := True;
  end;

  // Re-initialise inspector display edit button properly
  InitEdit;
  Inspector.Invalidate;
end;

// TAHMInspectorColourStringItem

class function TAHMInspectorColourStringItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMColourString);
end;

procedure TAHMInspectorColourStringItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifEditButton]); // + [iifAutoUpdate]);
end;

procedure TAHMInspectorColourStringItem.Edit;
begin
  // Use standard modify method to edit colour
  if UIObject.Modify then
    DoneEdit(True); // Cancel default editor

  // Re-initialise inspector display edit button properly
  InitEdit;
  Inspector.Invalidate;
end;

// TAHMInspectorMetaStringItem

class function TAHMInspectorMetaStringItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMMetaString);
end;

procedure TAHMInspectorMetaStringItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifValueList]);
end;

procedure TAHMInspectorMetaStringItem.GetValueList(const Strings: TStrings);
begin
  // Populate standard values from meta descriptor
  Strings.AddObject(EMPTY_UIOBJECT_NAME, nil);
  ApplicationManagerInstance.MetaDescriptor.MetaList.ListObjects(Strings);
end;

// TAHMInspectorFunctionStringItem

class function TAHMInspectorFunctionStringItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMFunctionString);
end;

procedure TAHMInspectorFunctionStringItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifValueList]);
end;

procedure TAHMInspectorFunctionStringItem.GetValueList(const Strings: TStrings);
begin
  // Populate standard values from function descriptor
  Strings.AddObject(EMPTY_UIOBJECT_NAME, nil);
  ApplicationManagerInstance.FunctionDescriptor.FunctionList.ListObjects(Strings);
end;

// TAHMInspectorTextStringItem

class function TAHMInspectorTextStringItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMTextString);
end;

procedure TAHMInspectorTextStringItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifEditButton]);
end;

procedure TAHMInspectorTextStringItem.Edit;
var
  Value: String;
begin
  Value := Data.AsString;

  // Use native language modify method to edit value
  with LanguageManagerInstance do
    if Languages[NativeLanguageName].ModifyValue(Value, DisplayName) then
    begin
      Data.AsString := Value;
      UIObject.Modified := True;
    end;

  // Re-initialise inspector display edit button properly
  InitEdit;
  Inspector.Invalidate;
end;

// TAHMInspectorTypefaceItem

class function TAHMInspectorTypefaceItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMTypeface);
end;

procedure TAHMInspectorTypefaceItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifEditButton]);
end;

procedure TAHMInspectorTypefaceItem.Edit;
begin
  // Use standard modify method to edit font
  if UIObject.Modify then
    DoneEdit(True); // Cancel default editor

  // Re-initialise inspector display edit button properly
  InitEdit;
  Inspector.Invalidate;
end;

// TAHMInspectorEnumItem

constructor TAHMInspectorEnumItem.Create(const AParent: TJvCustomInspectorItem; const AData: TJvCustomInspectorData);
var
  EnumInfo: IJclEnumerationTypeInfo;
  i: Integer;
begin
  inherited;

  // Create list of enumerated type member names
  FValues := TStringList.Create;

  EnumInfo := JclTypeInfo(Data.TypeInfo) as IJclEnumerationTypeInfo;
  for i := EnumInfo.MinValue to EnumInfo.MaxValue do
  begin
    // Remove two letter prefix and space camel cased words
    FValues.Add(FormatValueName(EnumInfo.Names[i]));
  end;
end;

destructor TAHMInspectorEnumItem.Destroy;
begin
  FValues.Free;

  inherited;
end;

function TAHMInspectorEnumItem.FormatValueName(const Name: String): String;
var
  Work: String;
  i: Integer;
begin
  // Remove two letter prefix from enumerated type member
  if (Length(Name) > 2) and (Name[1] in ['a'..'z']) and (Name[2] in ['a'..'z']) then
    Work := Copy(Name, 3, Length(Name))
  else
    Work := Name;

  // Insert spaces between camel cased type names
  Result := Copy(Work, 1, 1);
  for i := 2 to Length(Work) do
    if Work[i] in ['A'..'Z'] then
      Result := Result + ' ' + Work[i]
    else
      Result := Result + Work[i];
end;

function TAHMInspectorEnumItem.GetDisplayValue: String;
begin
  // Remove two letter prefix and space camel cased words
  Result := FormatValueName(inherited GetDisplayValue);
end;

procedure TAHMInspectorEnumItem.GetValueList(const Strings: TStrings);
begin
  // Populate list from cache
  Strings.Assign(FValues);
end;

procedure TAHMInspectorEnumItem.SetDisplayValue(const Value: string);
var
  OrdVal: Integer;
begin
  // Lookup ordinal value in our cache
  OrdVal := FValues.IndexOf(Value);
  if OrdVal <> -1 then Data.AsOrdinal := OrdVal;
end;

class procedure TAHMInspectorEnumItem.RegisterAsDefaultItem;
begin
  with TJvCustomInspectorData.ItemRegister do
  begin
    if IndexOf(Self) = -1 then
      Add(TJvInspectorTypeKindRegItem.Create(Self, tkEnumeration));
  end;
end;

class procedure TAHMInspectorEnumItem.UnregisterAsDefaultItem;
begin
  TJvCustomInspectorData.ItemRegister.Delete(Self);
end;

// TAHMInspectorSingleItem

constructor TAHMInspectorSingleItem.Create(const AParent: TJvCustomInspectorItem;
                                          const AData: TJvCustomInspectorData);
begin
  inherited;

  // Set default format
  Format := '0.00';
end;

class function TAHMInspectorSingleItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(Single);
end;

class procedure TAHMInspectorSingleItem.RegisterAsDefaultItem;
begin
  with TJvCustomInspectorData.ItemRegister do
  begin
    if IndexOf(Self) = -1 then
      Add(TJvInspectorTypeInfoRegItem.Create(Self, GetTypeInfo));
  end;
end;

class procedure TAHMInspectorSingleItem.UnregisterAsDefaultItem;
begin
  TJvCustomInspectorData.ItemRegister.Delete(Self);
end;

// TAHMInspectorClassItem

constructor TAHMInspectorClassItem.Create(const AParent: TJvCustomInspectorItem;
  const AData: TJvCustomInspectorData);
begin
  inherited Create(AParent, AData);
//  FOwners := TList.Create;
end;

function TAHMInspectorClassItem.GetUIObject: TAHMUIObject;
begin
  // Return owner of this property
  if Data is TJvInspectorPropData then
    FUIObject := TAHMUIObject(TJvInspectorPropData(Data).Instance)
  else
    FUIObject := nil;

  Result := FUIObject;
end;

function TAHMInspectorClassItem.GetSelectedObject: TAHMUIObject;
begin
  // Return value of this property
  Result := TAHMUIObject(Data.AsOrdinal);
end;

procedure TAHMInspectorClassItem.SetSelectedObject(Selected: TAHMUIObject);
begin
  // Set value of this property
  Data.AsOrdinal := Integer(Selected);
end;

class function TAHMInspectorClassItem.GetTypeInfo: Pointer;
begin
  // Descendants will override this to provide typeinfo for required type
  Result := nil;
end;

class procedure TAHMInspectorClassItem.RegisterAsDefaultItem;
begin
  with TJvCustomInspectorData.ItemRegister do
  begin
    if IndexOf(Self) = -1 then
      Add(TJvInspectorTypeInfoRegItem.Create(Self, GetTypeInfo));
  end;
end;

class procedure TAHMInspectorClassItem.UnregisterAsDefaultItem;
begin
  TJvCustomInspectorData.ItemRegister.Delete(Self);
end;

procedure TAHMInspectorClassItem.EditMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  // Override mouse handling so we can detect double click events
  if (Button = mbLeft) and (ssDouble in Shift) then
    if (iifValueList in Flags) then
    begin
      // This item has a combo box so, trigger item double clicked event
      if Assigned(TJvInspector(Inspector).OnItemDoubleClicked) then
        TJvInspector(Inspector).OnItemDoubleClicked(Inspector, Self);
    end
    else if (iifEditButton in Flags) then
    begin
      // This item has an edit button, so display edit dialog instead
      Edit;
    end;
end;

procedure TAHMInspectorClassItem.SetItemClassFlags(Value: TInspectorClassFlags);
begin
  inherited SetItemClassFlags(Value - [icfShowClassName, icfCreateMemberItems]);
end;

// TAHMInspectorClassListItem

procedure TAHMInspectorClassListItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifValueList] - [iifEditFixed]);
end;

// TAHMInspectorUIListItem

function TAHMInspectorUIListItem.GetDisplayValue: String;
begin
  Result := CLICK_TO_EDIT;
end;

procedure TAHMInspectorUIListItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifEditButton, iifEditFixed]);
end;

procedure TAHMInspectorUIListItem.Edit;
begin
  // Use standard modify method to edit list
  if TAHMUIObjectList(Data.AsOrdinal).Modify then UIObject.Modified := True;

  // Re-initialise inspector display edit button properly
  InitEdit;
  Inspector.Invalidate;
end;

// TAHMInspectorUIStateListItem

class function TAHMInspectorUIStateListItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMUIStateObjectList);
end;

// TAHMInspectorUIActionsItem

class function TAHMInspectorUIActionsItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMActionList);
end;

// TAHMInspectorUIAnimationsItem

class function TAHMInspectorUIAnimationsItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMAnimationList);
end;

// TAHMInspectorUIControlsItem

class function TAHMInspectorUIControlsItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMControlList);
end;

// TAHMInspectorUIContainersItem

class function TAHMInspectorUIContainersItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMContainerList);
end;

// TAHMInspectorUILayoutPositionsItem

class function TAHMInspectorUILayoutPositionsItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMLayoutPositionList);
end;

// TAHMInspectorUIMacroFunctionsItem

class function TAHMInspectorUIMacroFunctionsItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMMacroFunctionList);
end;

// TAHMInspectorUIMetaValuesItem

class function TAHMInspectorUIMetaValuesItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMMetaValueList);
end;

// TAHMInspectorUIObjectItem

class function TAHMInspectorUIObjectItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMUIObject);
end;

procedure TAHMInspectorUIObjectItem.GetValueList(const Strings: TStrings);
var
  ObjectList: TAHMUIObjectList;
begin
  // Update our UIObject property
  GetUIObject;

  // Get relevant list to use for populating values. This is optional as
  // descendants may return nil and populate their own list if required
  ObjectList := GetObjectList;
  if Assigned(ObjectList) then BuildValueList(Strings, ObjectList);
end;

procedure TAHMInspectorUIObjectItem.SetDisplayValue(const Value: string);
begin
  if Value = EMPTY_UIOBJECT_NAME then
  begin
    inherited SetDisplayValue('');
    Clear;
  end
  else
    inherited SetDisplayValue(Value);
end;

procedure TAHMInspectorUIObjectItem.BuildValueList(const Strings: TStrings; const List: TAHMUIObjectList);
begin
  // Delegate to method below without filtering applied
  BuildValueList(Strings, List, TAHMUIObject);
end;

procedure TAHMInspectorUIObjectItem.BuildValueList(const Strings: TStrings; const List: TAHMUIObjectList;
                                                   FilterClass: TAHMUIObjectClass);
var
  i: Integer;
  Obj: TAHMUIObject;
begin
  // Build list of items in our ui object owner list
  if Assigned(List) then
  begin
    Strings.AddObject(EMPTY_UIOBJECT_NAME, nil);
    for i := 0 to Pred(List.TotalCount) do
    begin
      Obj := TAHMUIObject(List.Objects[i]);
      if Obj is FilterClass then Strings.AddObject(Obj.Name, Obj);
    end;
  end;
end;

function TAHMInspectorUIObjectItem.GetObjectList: TAHMUIObjectList;
begin
  // Descendants must override this to provide relevant list object
  Result := nil;
end;

// TAHMInspectorUIAncestorItem

procedure TAHMInspectorUIAncestorItem.GetValueList(const Strings: TStrings);
var
  Owner: TAHMUIObjectList;
  Obj: TAHMUIObject;
  i: Integer;
begin
  inherited;

  // Build list of items in our ui object owner list
  if Assigned(FUIObject) and Assigned(FUIObject.Owner) then
  begin
    Owner := FUIObject.Owner;
    Strings.AddObject(EMPTY_UIOBJECT_NAME, nil);
    for i := 0 to Pred(Owner.TotalCount) do
      if TAHMUIObject(Owner.Objects[i]).IsEligibleAncestor(FUIObject) then
      begin
        Obj := TAHMUIObject(Owner.Objects[i]);
        if Obj <> nil then Strings.AddObject(Obj.Name, Obj);
      end;
  end;
end;

// TAHMInspectorUIColourItem

class function TAHMInspectorUIColourItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMColour);
end;

procedure TAHMInspectorUIColourItem.SetFlags(const Value: TInspectorItemFlags);
begin
  inherited SetFlags(Value + [iifOwnerDrawListFixed]);
end;

procedure TAHMInspectorUIColourItem.SetRects(const RectKind: TInspectorPaintRect; Value: TRect);
begin
  if RectKind = iprValue then
    Value.Left := Value.Left + (Value.Bottom - Value.Top) + 2;
  inherited SetRects(RectKind, Value);
end;

procedure TAHMInspectorUIColourItem.DoDrawListItem(Control: TWinControl; Index: Integer; Rect: TRect;
  State: TOwnerDrawState);
begin
  with TListBox(Control) do
  begin
    if odSelected in State then
      Canvas.Brush.Color := clHighlight;
    Canvas.FillRect(Rect);
    Rect.Top := Rect.Top + 1;
    Rect.Bottom := Rect.Bottom - 1;
    PaintColourValue(TAHMUIObject(Items.Objects[Index]), Items[Index], Canvas, Rect);
  end;
end;

procedure TAHMInspectorUIColourItem.DoMeasureListItem(Control: TWinControl; Index: Integer;
  var Height: Integer);
begin
  with Rects[iprValueArea] do
    Height := Bottom - Top + 2;
end;

procedure TAHMInspectorUIColourItem.DoMeasureListItemWidth(Control: TWinControl; Index: Integer;
  var Width: Integer);
begin
  with Rects[iprValueArea] do
    Width := Width + Bottom - Top + 2;
end;

procedure TAHMInspectorUIColourItem.DrawValue(const ACanvas: TCanvas);
var
  ARect: TRect;
begin
  ARect := Rects[iprValueArea];
  ACanvas.FillRect(ARect);
  PaintColourValue(TAHMUIObject(Data.AsOrdinal), DisplayValue, ACanvas, ARect);
  if Editing then DrawEditor(ACanvas);
end;

function TAHMInspectorUIColourItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.ColourList;
end;

// TAHMInspectorUIFillItem

class function TAHMInspectorUIFillItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMAbstractFill);
end;

function TAHMInspectorUIFillItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.FillList;
end;

// TAHMInspectorUIPlasmaItem

class function TAHMInspectorUIPlasmaItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMPlasma);
end;

function TAHMInspectorUIPlasmaItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.PlasmaList;
end;

// TAHMInspectorUICaptionItem

class function TAHMInspectorUICaptionItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMCaption);
end;

function TAHMInspectorUICaptionItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.CaptionList;
end;

// TAHMInspectorUIFontItem

class function TAHMInspectorUIFontItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMFont);
end;

function TAHMInspectorUIFontItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.FontList;
end;

// TAHMInspectorUIBitmapItem

class function TAHMInspectorUIBitmapItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMBitmap);
end;

function TAHMInspectorUIBitmapItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.BitmapList;
end;

// TAHMInspectorUIBackgroundItem

class function TAHMInspectorUIBackgroundItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMBackground);
end;

function TAHMInspectorUIBackgroundItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.BackgroundList;
end;

// TAHMInspectorUIForegroundItem

class function TAHMInspectorUIForegroundItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMForeground);
end;

function TAHMInspectorUIForegroundItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.ForegroundList;
end;

// TAHMInspectorUIEffectItem

class function TAHMInspectorUIEffectItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMEffect);
end;

function TAHMInspectorUIEffectItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.EffectList;
end;

// TAHMInspectorUIPlaceItem

class function TAHMInspectorUIPlaceItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMPlace);
end;

function TAHMInspectorUIPlaceItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.InterfaceDescriptor.PlaceList;
end;

// TAHMInspectorUILayoutItem

class function TAHMInspectorUILayoutItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMLayout);
end;

function TAHMInspectorUILayoutItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.InterfaceDescriptor.LayoutList;
end;

// TAHMInspectorUIGridItemItem

class function TAHMInspectorUIGridItemItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMGridItem);
end;

function TAHMInspectorUIGridItemItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.VisualDescriptor.GridItemList;
end;

// TAHMInspectorUIDisplayObjectItem

class function TAHMInspectorUIDisplayObjectItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMUIDisplayObject);
end;

function TAHMInspectorUIDisplayObjectItem.GetObjectList: TAHMUIObjectList;
begin
  // Double check, but style property should only be exposed for controls
  if GetUIObject is TAHMControl then
    Result := TAHMControl(FUIObject).Styles
  else
    Result := nil;
end;

// TAHMInspectorUIControlItem

class function TAHMInspectorUIControlItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMControl);
end;

function TAHMInspectorUIControlItem.GetObjectList: TAHMUIObjectList;
begin
  Result := ApplicationManagerInstance.ThemeManager.InterfaceDescriptor.ControlList;
end;

// TAHMInspectorUIInteractiveControlItem

class function TAHMInspectorUIInteractiveControlItem.GetTypeInfo: Pointer;
begin
  Result := TypeInfo(TAHMInteractiveControl);
end;

procedure TAHMInspectorUIInteractiveControlItem.GetValueList(const Strings: TStrings);
begin
  inherited;

  // For screens default control property list only controls in the screen
  if FUIObject is TAHMScreenLayout then
    BuildValueList(Strings, TAHMScreenLayout(FUIObject).NavigableControls)
  else
    BuildValueList(Strings, ApplicationManagerInstance.ThemeManager.InterfaceDescriptor.ControlList,
                   TAHMInteractiveControl);
end;


initialization
  // Register our custom editor classes
  TAHMInspectorFilenameItem.RegisterAsDefaultItem;
  TAHMInspectorMemoStringItem.RegisterAsDefaultItem;
  TAHMInspectorColourStringItem.RegisterAsDefaultItem;
  TAHMInspectorMetaStringItem.RegisterAsDefaultItem;
  TAHMInspectorFunctionStringItem.RegisterAsDefaultItem;
  TAHMInspectorTextStringItem.RegisterAsDefaultItem;
  TAHMInspectorTypefaceItem.RegisterAsDefaultItem;
  TAHMInspectorEnumItem.RegisterAsDefaultItem;
  TAHMInspectorSingleItem.RegisterAsDefaultItem;
  TAHMInspectorUIStateListItem.RegisterAsDefaultItem;
  TAHMInspectorUIActionsItem.RegisterAsDefaultItem;
  TAHMInspectorUIAnimationsItem.RegisterAsDefaultItem;
  TAHMInspectorUIControlsItem.RegisterAsDefaultItem;
  TAHMInspectorUIContainersItem.RegisterAsDefaultItem;
  TAHMInspectorUILayoutPositionsItem.RegisterAsDefaultItem;
  TAHMInspectorUIMacroFunctionsItem.RegisterAsDefaultItem;
  TAHMInspectorUIMetaValuesItem.RegisterAsDefaultItem;
  TAHMInspectorUIColourItem.RegisterAsDefaultItem;
  TAHMInspectorUIFillItem.RegisterAsDefaultItem;
  TAHMInspectorUIPlasmaItem.RegisterAsDefaultItem;
  TAHMInspectorUICaptionItem.RegisterAsDefaultItem;
  TAHMInspectorUIFontItem.RegisterAsDefaultItem;
  TAHMInspectorUIBitmapItem.RegisterAsDefaultItem;
  TAHMInspectorUIBackgroundItem.RegisterAsDefaultItem;
  TAHMInspectorUIForegroundItem.RegisterAsDefaultItem;
  TAHMInspectorUIEffectItem.RegisterAsDefaultItem;
  TAHMInspectorUIPlaceItem.RegisterAsDefaultItem;
  TAHMInspectorUILayoutItem.RegisterAsDefaultItem;
  TAHMInspectorUIGridItemItem.RegisterAsDefaultItem;
  TAHMInspectorUIDisplayObjectItem.RegisterAsDefaultItem;
  TAHMInspectorUIInteractiveControlItem.RegisterAsDefaultItem;
  TAHMInspectorUIControlItem.RegisterAsDefaultItem;
  TAHMInspectorUIAncestorItem.RegisterAsDefaultItem;

end.
